package implementations.dm_kernel.server;

import implementations.dm_kernel.MessageControlImpl;
import interfaces.kernel.JCL_message;
import interfaces.kernel.JCL_message_control;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.List;
import java.util.Map;

import commom.GenericConsumer;
import commom.GenericResource;

// exemplo de um consumidor !!!

/*
 * MESSAGES
 * 
 *  1 public boolean register(File[] f, String classToBeExecuted) {
    2 public boolean unRegister(String nickName) {
    4 public String execute(String objectNickname, Object... args) {
	5 public String execute(String className, String methodName, Object... args) {
	6 public JCL_result getResultBlocking(String ID) {
	7 public JCL_result getResultUnblocking(String ID) {
	8 public JCL_result removeResult(String ID) {
	9 public Object instantiateGlobalVar(String varName, Class<?> varType,
	10 public boolean instantiateGlobalVar(String varName, Object instance) {
	11 public boolean destroyGlobalVar(String varName) {
	12 public boolean setValue(String varName, Object value) {
	13 public boolean setValueUnlocking(String varName, Object value) {
	14 public JCL_result getValue(String varName) {
	15 public JCL_result getValueLocking(String varName) {
	16 public void destroy() {
	17 public boolean containsGlobalVar(String ninckName){
		
	METHOD DEPRECATED in JCL distributed version: public boolean register(Class<?> object, String nickName) {
	
	-1 slave register

 */

public class SocketConsumer<S extends Socket> extends GenericConsumer<S>{
	
	private Map<String,String[]> globalVarSlaves, slaves;
	private List<String> slavesIDs;
	
	public SocketConsumer(GenericResource<S> re, Map<String, String[]>globalVarSlaves, List<String> slavesIDs, Map<String, String[]> slaves) {
		
		super(re);	
		
		this.globalVarSlaves = globalVarSlaves;
		this.slavesIDs = slavesIDs;
		this.slaves = slaves;
	}

	@Override
	protected void doSomething(S str) {
		try{
			// TODO Auto-generated method stub
			ObjectInputStream in = new ObjectInputStream(str.getInputStream());
			JCL_message msg = (JCL_message) in.readObject();
			System.err.println(msg.getType());
			switch (msg.getType()){
			case 1:{						
				
				String[] hostPort = RoundRobin.next(slavesIDs, this.slaves);
				JCL_message_control mc = new MessageControlImpl();
				mc.setRegisterData(hostPort);
				ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
				out.writeObject(mc);
				out.flush();
				out.close();							
				in.close();				
				break;
			}
			case 2:{				
								
				JCL_message_control mc = new MessageControlImpl();
				String[] hostPort =new String[this.slaves.size()*2];
				int i=0;
				
				for(String[] oneHostPort: this.slaves.values()){
					hostPort[i] = oneHostPort[0];
					hostPort[i+1] = oneHostPort[1];
					i+=2;
				}
				
				mc.setRegisterData(hostPort);
				ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
				out.writeObject(mc);
				out.flush();
				out.close();					
				in.close();	
				break;
			}
			
			case 4:{				
				JCL_message_control mc = new MessageControlImpl();
				String[] hostPort =RoundRobin.next(slavesIDs, this.slaves);
				mc.setRegisterData(hostPort);
				ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
				out.writeObject(mc);
				out.flush();
				out.close();							
				in.close();
				break;
			}
			case 5:{				
				JCL_message_control mc = new MessageControlImpl();
				String[] hostPort =RoundRobin.next(slavesIDs, this.slaves);
				mc.setRegisterData(hostPort);
				ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
				out.writeObject(mc);
				out.flush();
				out.close();							
				in.close();
				break;
			}
			
			case 9:{				
				synchronized (globalVarSlaves) {
					JCL_message_control aux = (JCL_message_control) msg;
					if(globalVarSlaves.containsKey(aux.getRegisterData()[0])){
						JCL_message_control mc = new MessageControlImpl();
						String[] hostPort = {};
						mc.setRegisterData(hostPort);
						ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
						out.writeObject(mc);
						out.flush();
						out.close();
						
					}else{
						String[] hostPort = RoundRobin.next(slavesIDs, this.slaves);
						globalVarSlaves.put(aux.getRegisterData()[0],hostPort);
						JCL_message_control mc = new MessageControlImpl();
						mc.setRegisterData(hostPort);
						ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
						out.writeObject(mc);
						out.flush();
						out.close();							
					}
					
					in.close();
				}	
				break;
			}
			case 10:{				
				synchronized (globalVarSlaves) {
					JCL_message_control aux = (JCL_message_control) msg;
					if(globalVarSlaves.containsKey(aux.getRegisterData()[0])){
						JCL_message_control mc = new MessageControlImpl();
						String[] hostPort = {};
						mc.setRegisterData(hostPort);
						ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
						out.writeObject(mc);
						out.flush();
						out.close();
						
					}else{
						String[] hostPort = RoundRobin.next(slavesIDs, this.slaves);
						globalVarSlaves.put(aux.getRegisterData()[0],hostPort);
						JCL_message_control mc = new MessageControlImpl();
						mc.setRegisterData(hostPort);
						ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
						out.writeObject(mc);
						out.flush();
						out.close();							
					}
					
					in.close();
				}
				break;
			}
			case 11:{				
				synchronized (globalVarSlaves) {
					JCL_message_control aux = (JCL_message_control) msg;
					if(globalVarSlaves.containsKey(aux.getRegisterData()[0])){
						JCL_message_control mc = new MessageControlImpl();
						String[] hostPort = globalVarSlaves.remove(aux.getRegisterData()[0]);
						mc.setRegisterData(hostPort);
						ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
						out.writeObject(mc);
						out.flush();
						out.close();
						
					}else{
						JCL_message_control mc = new MessageControlImpl();
						String[] hostPort ={};
						mc.setRegisterData(hostPort);
						ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
						out.writeObject(mc);
						out.flush();
						out.close();							
					}
					
					in.close();
				}	
				break;
			}
			case 12:{
				JCL_message_control aux = (JCL_message_control) msg;
				if(globalVarSlaves.containsKey(aux.getRegisterData()[0])){
					JCL_message_control mc = new MessageControlImpl();
					String[] hostPort = globalVarSlaves.get(aux.getRegisterData()[0]);
					mc.setRegisterData(hostPort);
					ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
					out.writeObject(mc);
					out.flush();
					out.close();
					
				}else{
					String[] hostPort = {};
					JCL_message_control mc = new MessageControlImpl();
					mc.setRegisterData(hostPort);
					ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
					out.writeObject(mc);
					out.flush();
					out.close();							
				}
				
				in.close();
				
				break;
			}
			case 13:{				
				JCL_message_control aux = (JCL_message_control) msg;
				if(globalVarSlaves.containsKey(aux.getRegisterData()[0])){
					JCL_message_control mc = new MessageControlImpl();
					String[] hostPort = globalVarSlaves.get(aux.getRegisterData()[0]);
					mc.setRegisterData(hostPort);
					ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
					out.writeObject(mc);
					out.flush();
					out.close();
					
				}else{
					String[] hostPort = {};
					JCL_message_control mc = new MessageControlImpl();
					mc.setRegisterData(hostPort);
					ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
					out.writeObject(mc);
					out.flush();
					out.close();							
				}
				
				in.close();
				
				break;
			}
			case 14:{				
				JCL_message_control aux = (JCL_message_control) msg;
				if(globalVarSlaves.containsKey(aux.getRegisterData()[0])){
					JCL_message_control mc = new MessageControlImpl();
					String[] hostPort = globalVarSlaves.get(aux.getRegisterData()[0]);
					mc.setRegisterData(hostPort);
					ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
					out.writeObject(mc);
					out.flush();
					out.close();
					
				}else{
					String[] hostPort = {};
					JCL_message_control mc = new MessageControlImpl();
					mc.setRegisterData(hostPort);
					ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
					out.writeObject(mc);
					out.flush();
					out.close();							
				}
				
				in.close();
				
				break;
			}
			case 15:{				
				JCL_message_control aux = (JCL_message_control) msg;
				if(globalVarSlaves.containsKey(aux.getRegisterData()[0])){
					JCL_message_control mc = new MessageControlImpl();
					String[] hostPort = globalVarSlaves.get(aux.getRegisterData()[0]);
					mc.setRegisterData(hostPort);
					ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
					out.writeObject(mc);
					out.flush();
					out.close();
					
				}else{
					String[] hostPort = {};
					JCL_message_control mc = new MessageControlImpl();
					mc.setRegisterData(hostPort);
					ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
					out.writeObject(mc);
					out.flush();
					out.close();							
				}
				
				in.close();
				
				break;
			}
			case 16:{	
				//devemos parar todos os slaves antes...
				JCL_message_control mc = new MessageControlImpl();
				String[] hostPort =new String[this.slaves.size()*2];
				int i=0;
				
				for(String[] oneHostPort: this.slaves.values()){
					hostPort[i] = oneHostPort[0];
					hostPort[i+1] = oneHostPort[1];
					i+=2;
				}
				
				mc.setRegisterData(hostPort);
				ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
				out.writeObject(mc);
				out.flush();
				out.close();
				
				in.close();
				
				re.stopServer();
				re.setFinished();
				break;
			}
			
			case 17:{				
				JCL_message_control aux = (JCL_message_control) msg;
				JCL_message_control mc = new MessageControlImpl();
				
				if(globalVarSlaves.containsKey(aux.getRegisterData()[0]))
					mc.setRegisterData("true");
				else mc.setRegisterData("false");
				
				
				ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
				out.writeObject(mc);
				out.flush();
				out.close();
				
				in.close();
				
				break;
			}
			
			
			case -1:{	
				JCL_message_control aux = (JCL_message_control) msg;
				
				if(aux.getRegisterData().length==3){
					synchronized (slaves) {
						String slaveName = aux.getRegisterData()[0];
						String address = aux.getRegisterData()[1];
						String port = aux.getRegisterData()[2];
						
						if(slaves.containsKey(slaveName)){
							String[] empty = {};
							JCL_message_control mc = new MessageControlImpl();
							mc.setRegisterData(empty);
							ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
							out.writeObject(mc);
							out.flush();
							out.close();
						}else{
							String[] hostPort = {address, port};
							
							slaves.put(slaveName, hostPort);
							slavesIDs.add(slaveName);
							
							String[] empty = {"registered"};
							JCL_message_control mc = new MessageControlImpl();
							mc.setRegisterData(empty);
							ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
							out.writeObject(mc);
							out.flush();
							out.close();
							
							System.err.println("JCL HOST " + slaveName + " registered!");
						}
					}
				}else{
					String[] empty = {};
					JCL_message_control mc = new MessageControlImpl();
					mc.setType(-1);
					mc.setRegisterData(empty);
					ObjectOutputStream out = new ObjectOutputStream(str.getOutputStream());
					out.writeObject(mc);
					out.flush();
					out.close();
				}
				
				break;
			}
			
			}
			
			in.close();
			str.close();
				
		}catch (Exception e){
			e.printStackTrace();
			
		}
				
	}	

}
